namespace SimpleWebServices.Web.UI.Html.Validation
{
    using System;
    using System.Configuration;
    using System.Xml.Serialization;
    using SimpleWebServices;
    using SimpleWebServices.Data;
    using SimpleWebServices.Web.UI.Html.Elements;
    using Xunit;

    public sealed class ValidatorSettingsFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<ValidatorSettings>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("validator")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            string type = typeof(StandardTextValidator).FullName;

            string xml =
                "<validator display='label' for='input' type='" + type + "'>" +
                    "<data><value name='foo'>bar</value></data>" +
                "</validator>";

            ValidatorSettings obj = xml.Deserialize<ValidatorSettings>();

            Assert.Equal<string>("bar", obj.Data["foo"]);
            Assert.Equal<string>("label", obj.Display);
            Assert.Equal<string>("input", obj.For);
            Assert.Equal<string>(type, obj.Type);
        }

        [Fact]
        public void deserializeEmpty()
        {
            ValidatorSettings obj = "<validator/>".Deserialize<ValidatorSettings>();

            Assert.NotNull(obj.Data);
            Assert.Null(obj.Display);
            Assert.Null(obj.For);
            Assert.Null(obj.Type);
        }

        [Fact]
        public void serialize()
        {
            string type = typeof(StandardTextValidator).FullName;

            ValidatorSettings obj = new ValidatorSettings
            {
                Display = "label",
                For = "input",
                Type = type,
                Data =
                {
                    { "foo", "bar" }
                }
            };

            string xpath = "1=count(/validator[@display='label'][@for='input'][@type='" + type + "']/data/value[@name='foo'][text()='bar'])";

            Assert.True((bool)obj.Serialize().CreateNavigator().Evaluate(xpath));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new ValidatorSettings());
        }

        [Fact]
        public void prop_Data()
        {
            Assert.True(new PropertyExpectations(typeof(ValidatorSettings).GetProperty("Data"))
                .XmlElement("data")
                .TypeIs<DataCollection>()
                .DefaultValueIsNotNull()
                .Set(null)
                .Set(new DataCollection())
                .Result);
        }

        [Fact]
        public void prop_Display()
        {
            Assert.True(new PropertyExpectations(typeof(ValidatorSettings).GetProperty("Display"))
                .XmlAttribute("display")
                .IsAutoProperty<Name>()
                .Result);
        }

        [Fact]
        public void prop_For()
        {
            Assert.True(new PropertyExpectations(typeof(ValidatorSettings).GetProperty("For"))
                .XmlAttribute("for")
                .IsAutoProperty<Name>()
                .Result);
        }

        [Fact]
        public void prop_Type()
        {
            Assert.True(new PropertyExpectations(typeof(ValidatorSettings).GetProperty("Type"))
                .XmlAttribute("type")
                .IsAutoProperty<string>()
                .Result);
        }

        [Fact]
        public void op_AddValidator_Fieldset()
        {
            string type = typeof(StandardTextValidator).FullName;

            ValidatorSettings obj = new ValidatorSettings
            {
                Display = "label",
                For = "input",
                Type = type
            };

            Label label = new Label { Id = "label" };
            Fieldset fieldset = new Fieldset
            {
                Id = "input",
                Elements =
                {
                    label
                }
            };

            obj.AddValidator(fieldset);

            Assert.IsType<StandardTextValidator>(fieldset.Validator);
            Assert.Same(label, fieldset.Validator.Display);
        }

        [Fact]
        public void op_AddValidator_Form()
        {
            string type = typeof(StandardTextValidator).FullName;

            ValidatorSettings obj = new ValidatorSettings
            {
                Display = "label",
                For = "input",
                Type = type,
                Data =
                {
                    { "MaxLength", "100" }
                }
            };

            Label label = new Label { Id = "label" };
            Form form = new Form
            {
                Elements =
                {
                    label,
                    new TextInput { Id = "input" }
                }
            };

            obj.AddValidator(form);

            Assert.IsType<StandardTextValidator>((form["input"] as IValidation).Validator);
            Assert.Same(label, (form["input"] as TextInput).Validator.Display);
            Assert.Equal<int?>(100, ((form["input"] as TextInput).Validator as StandardTextValidator).MaxLength);
        }

        [Fact]
        public void op_AddValidator_Form_typeIsNotIValidate()
        {
            ValidatorSettings obj = new ValidatorSettings
            {
                Type = typeof(DateTime).FullName
            };

            Assert.Throws<ConfigurationErrorsException>(() => obj.AddValidator(new Form()));
        }

        [Fact]
        public void op_AddValidator_Form_displayIsNotIInnerHtml()
        {
            ValidatorSettings obj = new ValidatorSettings
            {
                Display = "invalid",
                For = "input",
                Type = typeof(StandardTextValidator).FullName
            };

            Form form = new Form
            {
                Elements =
                {
                    new Image { Id = "invalid" },
                    new TextInput { Id = "input" }
                }
            };

            Assert.Throws<ConfigurationErrorsException>(() => obj.AddValidator(form));
        }

        [Fact]
        public void op_AddValidator_Form_forIsNotIControl()
        {
            ValidatorSettings obj = new ValidatorSettings
            {
                Display = "label",
                For = "invalid",
                Type = typeof(StandardTextValidator).FullName
            };

            Form form = new Form
            {
                Elements =
                {
                    new Label { Id = "label" },
                    new Image { Id = "invalid" }
                }
            };

            Assert.Throws<ConfigurationErrorsException>(() => obj.AddValidator(form));
        }

        [Fact]
        public void op_AddValidator_FormNull()
        {
            Assert.Throws<ArgumentNullException>(() => new ValidatorSettings().AddValidator(null as Form));
        }
    }
}